use honeybee::actors::tcpconnecters::TcpConnectersActor;
use honeybee::prelude::*;
use honeybee::Result;
use honeybee_proto::room;

use crate::room_manager::{Add, AddResult, RoomManager};

#[derive(Default)]
pub struct RoomTestActor {
    usc_server: Option<Addr<TcpConnectersActor>>,
}

impl RoomTestActor {
    fn usc_server(&self) -> &Addr<TcpConnectersActor> {
        self.usc_server.as_ref().unwrap()
    }
}

impl Service for RoomTestActor {}

#[async_trait::async_trait]
impl Actor for RoomTestActor {
    fn name(&self) -> &str {
        "RoomTestActor"
    }

    async fn started(&mut self, ctx: &mut Context<Self>) -> Result<()> {
        info!("room actor:{} started", ctx.actor_id());
        let actor_center = ActorCenter::from_registry().await?;
        self.usc_server = Some(actor_center.call(Query::new("usc_server")).await?);

        let router = ctx.get_router().await?;
        router.register::<proto::ReqHelloWorld>();
        router.register::<proto::UserOnlineNotifyRoom>();

        router.register_rpc::<proto::Add>();
        router.register_rpc::<proto::GetValue>();
        router.register_rpc::<proto::GetScores>();

        router.register_nats::<proto::NatsMsgTest>();

        let room_manager = RoomManager::from_registry().await?;
        let _ = room_manager.async_call(ctx.address(), Add(1, 2));
        Ok(())
    }

    async fn stopped(&mut self, _ctx: &mut Context<Self>) {
        info!("room actor stoped");
    }
}

#[async_trait::async_trait]
impl AnyHandler<AddResult> for RoomTestActor {
    async fn handle(&mut self, _ctx: &mut Context<Self>, msg: AddResult) -> Result<()> {
        debug!("xxxxxxx async call 1 + 2 = {}", msg.0);
        Ok(())
    }
}

#[async_trait::async_trait]
impl Handler<NetMsg<proto::ReqHelloWorld>> for RoomTestActor {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        msg: NetMsg<proto::ReqHelloWorld>,
    ) -> Result<()> {
        let (source_addr, msg) = (msg.source, msg.msg);
        debug!(
            "room actor process message:{:?} source_addr:{}",
            msg,
            source_addr.actor_id()
        );

        source_addr.send_remote(proto::RspHelloWorld { a: msg.a, b: msg.b })?;

        Ok(())
    }
}

#[async_trait::async_trait]
impl Handler<NetMsg<proto::UserOnlineNotifyRoom>> for RoomTestActor {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        msg: NetMsg<proto::UserOnlineNotifyRoom>,
    ) -> Result<()> {
        let (source_addr, msg) = (msg.source, msg.msg);
        debug!(
            "room actor process message:{:?} source_addr:{}",
            msg,
            source_addr.actor_id()
        );

        let usc_server = self.usc_server();
        usc_server.send_to_app_user(msg.uid, proto::RoomChangeAppUserData { a: 1 });
        //usc_server.send_to_all_app_user(proto::RoomChangeAppUserData { a: 1 });
        let rsp = room::RspCreateRoomState { successed: true };
        usc_server.send_to_user(msg.uid, rsp);
        //usc_server.send_to_all_user(rsp);

        Ok(())
    }
}

#[async_trait::async_trait]
impl Handler<NetRpcMsg<proto::Add>> for RoomTestActor {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        msg: NetRpcMsg<proto::Add>,
    ) -> Result<u32> {
        let msg = msg.msg;
        Ok(msg.0 + msg.1)
    }
}

#[async_trait::async_trait]
impl Handler<NetRpcMsg<proto::GetValue>> for RoomTestActor {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        _msg: NetRpcMsg<proto::GetValue>,
    ) -> Result<Vec<String>> {
        Ok(vec!["hello.world".to_string(), "xxxx".to_string()])
    }
}

#[async_trait::async_trait]
impl Handler<NetRpcMsg<proto::GetScores>> for RoomTestActor {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        _msg: NetRpcMsg<proto::GetScores>,
    ) -> Result<proto::Scores> {
        Ok(proto::Scores {
            scores: vec![1, 15, 60, 100],
        })
    }
}

#[async_trait::async_trait]
impl Handler<NatsMsg<proto::NatsMsgTest>> for RoomTestActor {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        msg: NatsMsg<proto::NatsMsgTest>,
    ) -> Result<()> {
        debug!("receive nats message:{:?} reply:{}", msg.msg, msg.reply);
        Ok(())
    }
}
